[Android][Kotlin] KotlinでAndroidアプリケーションを記述する 01 [Hello Kotlin]
こんにちは。こむろです。先日SAPを会場に行われたDevelopersIO 2015にお越しいただいた皆様、ありがとうございました。
自分は、引き続きこのブログでは統一感のあまりない雑多な技術記事を放出していこうかと思っていますので、よろしくお願いします。
Androidアプリケーション開発のAlternative開発言語として静かな注目を集めているKotlinについて調べてみました。
kotlin
Kotlinは、皆様ご存知の超有名IDEであるIntelliJ IDEAの開発元であるJetBrains社が開発しているプログラミング言語です。
Wikipediaの説明を見てみると、
オペーレーティング・システムによらずJava仮想マシン上で動く。Java言語が書かれたプログラムと同じほど速くコンパイルされ同じほど速く動作するとしている。
とあります。
Javaと非常に親和性が高いようです。さらにこの言語を使ったAndroidアプリケーションの開発も可能なようです。今までのAndroidアプリケーション開発ではJava6(部分的にJava7)でしたが、色々と限界が見えてる昨今。AlternativeなAndroidアプリケーション開発言語として期待できそうです。
気になったのが、
Java との相互運用性(Kotlin から Java を呼び出すことも、Java から Kotlin を呼び出すこともできる)
これならば部分的に導入することが出来るので、徐々にチーム内に侵食させることができそうです。
Kotlinを導入する
今回は、Android Studioにkotlinを導入してみます。自分の環境は以下のとおりです。
- OS: Mac OSX Yosemite 10.10.2
- IDE: Android Studio 0.8.9
早速Kotlinを導入してみましょう。
Pluginを追加する
Android Studio>Preferencesを選択し、設定画面を開きます。pluginを選択します。以下のような画面になるので、下のInstall JetBrains Pluginsをクリックします。
Pluginブラウザが起動するので、kotlinを検索します。kotlinが検索されるので、Install Pluginをクリックします。
Yesをクリック。
インストールが完了すると、再起動を要求されます。
再起動します。
これでkotlinの導入は完了です。
確認
確認してみます。適当なプロジェクトを作成します。
今回は「KotlinAndroid」という名前でAndroidプロジェクトを作成しましょう。今回はテンプレートを「Blank Activity with Fragment」を選択しました。
さて、ここまではいつも通りです。ナビゲーションツリーで右クリックをしてメニューを表示、「New」を選択してみましょう。「kotlin File」が確認できます。
とりあえず問題なくPluginは導入できたようです。
Java → Kotlin
KotlinのPluginを入れたお陰で、Javaファイルを一発で変換できる機能が追加されています。今作成したAndroidプロジェクトのActivityファイルをそのままKotlinに変換して試してみましょう。
Code>Convert Java File to Kotlin Fileを選択すると、変換が実行されます。
変換後
package kotlin.android.classmethod.jp.kotlinandroid import android.app.Activity import android.app.Fragment import android.os.Bundle import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.view.View import android.view.ViewGroup public class MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_my) if (savedInstanceState == null) { getFragmentManager().beginTransaction().add(R.id.container, PlaceholderFragment()).commit() } } override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.my, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. val id = item.getItemId() if (id == R.id.action_settings) { return true } return super.onOptionsItemSelected(item) } /** * A placeholder fragment containing a simple view. */ public class PlaceholderFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle): View? { val rootView = inflater.inflate(R.layout.fragment_my, container, false) return rootView } } }
かなり短くなりました。必要な部分だけ記述することが出来て非常に見やすくなっています。
javaパッケージをkotlinにリネームする
JavaファイルのConvertだけでは、そのまま実行することは出来ません。rootパッケージもきちんと変更してあげる必要があります。kotlinファイルは、javaパッケージ配下ではなく、kotlinパッケージ配下に配置する必要があります。
javaパッケージを右クリックしてリファクタメニューを表示します。
javaをkotlinに書き換えてRefactorを実行します。
build.gradleをKotlin用に設定する
kotlinパッケージ以下をコンパイル対象に含めるために、build.graldeを修正する必要があります。メニューから一発で全て設定してくれるので簡単です。
Tools>Kotlin>Configure Kotlin in Projectを選択します。
これを選択すると自動的にbuild.gradleにKotlin用の設定が追記されます。
apply plugin: 'com.android.application' // ↓追加された apply plugin: 'kotlin-android' android { compileSdkVersion 21 buildToolsVersion "20.0.0" defaultConfig { applicationId "sample.android.classmethod.jp.kotlinandroid" minSdkVersion 18 targetSdkVersion 21 versionCode 1 versionName "1.0" } // ↓追加された sourceSets { main.java.srcDirs += 'src/main/kotlin' } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) // ↓追加された compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } // ↓追加された buildscript { ext.kotlin_version = '0.11.91.1' repositories { mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } repositories { mavenCentral() }
プロジェクトをビルド
これでKotlinでAndroidアプリケーションを開発する準備ができました。プロジェクトをビルドします。
Build>Make Projectを選択します。
Androidアプリケーションを実行する
ビルドに成功したらいつも通り、Androidアプリケーションを実行しましょう。正常に起動すれば以下の様な画面が表示されます。
以下のようなエラーが表示された場合は、一部ソースを修正する必要があります。
04-09 16:34:05.262 23786-23786/sample.android.classmethod.jp.kotlinandroid E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: sample.android.classmethod.jp.kotlinandroid, PID: 23786 java.lang.RuntimeException: Unable to start activity ComponentInfo{sample.android.classmethod.jp.kotlinandroid/sample.android.classmethod.jp.kotlinandroid.MyActivity}: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter savedInstanceState at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2237) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2286) at android.app.ActivityThread.access$800(ActivityThread.java:144) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1246) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:212) at android.app.ActivityThread.main(ActivityThread.java:5137) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:718) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter savedInstanceState at sample.android.classmethod.jp.kotlinandroid.MyActivity$PlaceholderFragment.onCreateView(MyActivity.kt) at android.app.Fragment.performCreateView(Fragment.java:1700) at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:894) at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1066) at android.app.BackStackRecord.run(BackStackRecord.java:684) at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1455) at android.app.Activity.performStart(Activity.java:5240) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2210) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2286) at android.app.ActivityThread.access$800(ActivityThread.java:144) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1246) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:212) at android.app.ActivityThread.main(ActivityThread.java:5137) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:718) at dalvik.system.NativeStart.main(Native Method)
修正する箇所は、PlaceHolderFragment#onCreateView()です。以下のように修正してください。
/** * A placeholder fragment containing a simple view. */ public class PlaceholderFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val rootView = inflater.inflate(R.layout.fragment_my, container, false) return rootView } }
修正した箇所は、savedInstanceState: Bundleです。この値はnullを許容する必要が有るため、値をNullableに変更する必要があります。「?」を付与します。これで正常に実行できると思います。
まとめ
Androidアプリケーションを今までJavaで書いていた人にとっても、かなり取っ付きやすい言語だという印象を受けました。また、Java8などを利用して、あの機能があったら良いのになぁと思うことがあると、さらに魅力的かもしれません。今後は少しずつKotlinでAndroidアプリケーションの方を記述していってみようかと思います。
今後は、Javaのソースコードと混在させて使う、Kotlinの言語としての特性などを調べていきたいと思います。非常に魅力的なプログラミング言語だと思います!ことりんかわいいよコトリン